#include "BigNum.h"


BigNum::BigNum(void):lower_index(0),toper_index(0)
{
}

BigNum::BigNum(BigNum& r_value)
{
	this->clear();
	int i = r_value.getToperIndex();
	int low = r_value.getLowerIndex();
	for(;i>=low;--i)
	{
		this->push_back(r_value[i]);
	}
}


BigNum::~BigNum(void)
{
	clear();
}

BigNum BigNum::operator +=(BigNum& r_value)
{
	int carry_bit_num = 0;
	int r_index = r_value.getLowerIndex();
	int this_index = getLowerIndex();
	for (int i = 0;i < r_value.size();++i)
	{
		int temp_result =0;
		if( 0 !=carry_bit_num)
		{
			temp_result+=carry_bit_num;
			carry_bit_num =0;
		}
		int temp_b=(r_value[r_index]-'0');
		if (this_index > toper_index ||this->empty())
		{
			carry_bit_num = (temp_b+temp_result)/10;
			char temp_c = (temp_b+temp_result)%10+'0';
			this->push_back(r_value[r_index]);
		}
		else
		{
			int temp = *(this->m_it_map[this_index]) -'0';
			carry_bit_num = (temp_b+temp+temp_result)/10;
			char temp_c = (temp+temp_b+temp_result)%10+'0';
			*(this->m_it_map[i])=temp_c;
		}
		
		++this_index;
		++r_index;
	}
	if(0 != carry_bit_num)
	{
		char insert_char = (char)(carry_bit_num + '0');
		this->push_back(insert_char);
	}
	return *this;
}



int BigNum::size()
{
	return m_num.size();
}

void BigNum::push_back(char& p_value)
{
	m_num.push_back(p_value);
	if(m_it_map.empty())
	{
		m_it_map.insert(std::pair<int,ITR>(0,--m_num.end()));

	}
	else
	{
		++toper_index;
		m_it_map.insert(std::pair<int,ITR>(toper_index,--m_num.end()));
	}
	
}

void BigNum::push_front(char& p_value)
{
	m_num.push_front(p_value);
	if(m_it_map.empty())
	{
		m_it_map.insert(std::pair<int,ITR>(0,m_num.begin())); 
	}
	else
	{
		--lower_index;
		m_it_map.insert(std::pair<int,ITR>(lower_index,m_num.begin())); 
	}
}

int BigNum::getLowerIndex()
{
	return lower_index;
}

int BigNum::getToperIndex()
{
	return toper_index;
}

char& BigNum::operator[](int r_value)
{
	return *(m_it_map[r_value]);
}

BigNum BigNum::operator*(BigNum& r_value)
{
	if(this->empty())
	{
		return  BigNum();
	}
	BigNum result;
	BigNum temp_result;
	int bit_num = 0;
	char cover_bit = '0';
	int r_index = r_value.getLowerIndex();
	for (int i = 0;i< r_value.size();++i)
	{
		if(!temp_result.empty())
		{
			temp_result.clear();
		}
		if('0' != r_value[r_index])
		{
			singleTime(temp_result,r_value[r_index]);
			for(int j = 0;j<bit_num;++j)
			{
				temp_result.push_front(cover_bit);
			}
			result+=temp_result;
		}
		++bit_num;
		++r_index;
	}
	return result;
}

void BigNum::singleTime(BigNum& temp_result,char curr_bit)
{
	int r_num = curr_bit - '0';
	int this_num = 0;
	int carry_bit_num = 0;
	int temp_result_num = 0;
	char result_char;
	for (int i = this->getLowerIndex();i<=this->getToperIndex();++i)
	{
		this_num = (*this)[i] - '0';
		if(0 != carry_bit_num)
		{
			temp_result_num += carry_bit_num;
			carry_bit_num = 0;
		}
		temp_result_num += r_num * this_num;
		result_char = (temp_result_num%10)+'0';
		temp_result.push_back(result_char);
		carry_bit_num = temp_result_num/10;
		temp_result_num = 0;
	}
	if(0 != carry_bit_num)
	{
		result_char = carry_bit_num +'0';
		temp_result.push_back(result_char);
	}

}

void BigNum::clear()
{
	m_it_map.clear();
	m_num.clear();
	toper_index = 0;
	lower_index = 0;
}

bool BigNum::empty()
{
	return m_it_map.empty();
}

BigNum BigNum::operator=(BigNum& r_value)
{
	if(this == &r_value)
	{
		return *this;
	}
	this->clear();
	int i = r_value.getToperIndex();
	int low = r_value.getLowerIndex();
	for(;i>=low;--i)
	{
		this->push_back(r_value[i]);
	}
	return *this;
}


std::ostream& operator<<(std::ostream& out,BigNum& obj)
{
	for (int i =obj.getToperIndex(); i>=obj.getLowerIndex();--i)
	{
		out<<obj[i];
	}
	return out;
}

// std::istream& operator >>(std::istream& in,BigNum& obj)
// {
	
// 	char temp_input;
// 	while(temp_input=in.get())
// }